package XunChunCPU.ID

import chisel3._
import chisel3.util._
import XunChunCPU.common.CommonConfig._ 
import XunChunCPU.common.Bundles._

class Control extends Module {
    val io = IO(new Bundle {
        // 从Decode传入控制信息、指令信息和PC信息
        val controlInfo = Flipped(new ControlInfo)
        val instr = Input(UInt(instrLen.W))
        val pc = Input(UInt(instrAddrLen.W))
        // 获取到的寄存器信息
        val rsData = Input(UInt(regLen.W))
        val rtData = Input(UInt(regLen.W))
        // 获取到的旁路信息
        val bypassFromExe = Flipped(new ByPassBundle)
        val bypassFromMem = Flipped(new ByPassBundle)
        // 寄存器读取驱动
        val rsAddr = Output(UInt(regAddrLen.W))                     //
        val rtAddr = Output(UInt(regAddrLen.W))                     //
        // NextPC以及驱动读取下一条指令
        val NPC_Type = Output(Bool())
        val NextPC = Output(UInt(instrAddrLen.W))                   //
        // 执行信息 A操作数，B操作数，是否写回，写回地址，  OP码，AB是否来自寄存器，来自地址
        val exeInfo = new ExeInfo                                   //
        // ready
        val ready_in = Input(Bool())
        val ready_out = Output(Bool())                              //
        val valid_in = Input(Bool())
        val valid_out = Output(Bool())
        // EXE来的旁路2
        val isLBandLW = Input(Bool())
        val wregAddr = Input(UInt(5.W))
        // Stall
        val stallFromID = Output(Bool())
    })
    // 要更新的信息主要为PC，操作数，和Valid与Ready
    // 以下是从指令获取的信息
    val rsAddr = Wire(UInt(regAddrLen.W))
    val rtAddr = Wire(UInt(regAddrLen.W))
    val rdAddr = Wire(UInt(regAddrLen.W))
    val sa = Wire(UInt(5.W))
    val imm = Wire(UInt(immLen.W))
    val offset = Wire(UInt(offsetLen.W))
    val instrAddrImm = Wire(UInt(instrAddrImmLen.W))

    // 记录是否是LB和LW指令
    val lbandlw = RegInit(false.B)
    rsAddr := io.instr(25,21)
    rtAddr := io.instr(20,16)
    rdAddr := io.instr(15,11)
    sa := io.instr(10,6)
    imm := io.instr(15,0)
    offset := io.instr(15,0)
    instrAddrImm := io.instr(25,0)
    // 立即数符号拓展
    val immAfterExt = Wire(UInt(32.W))
    when(io.controlInfo.immExtType === SignExt && imm(15) === 1.U) {
        immAfterExt := Cat(0xffff.U(16.W),imm)
    }.otherwise{
        immAfterExt := Cat(0x0000.U(16.W),imm)
    }
    val trueRSData = Wire(UInt(regLen.W))
    val trueRTData = Wire(UInt(regLen.W))
    // 处理旁路
    when(io.bypassFromExe.regAddr =/= rsAddr && io.bypassFromMem.regAddr =/= rsAddr){
        trueRSData := io.rsData
    }.elsewhen(io.bypassFromExe.regAddr === rsAddr && rsAddr =/= 0.U && io.bypassFromMem.regAddr === rsAddr){
        trueRSData := io.bypassFromExe.regData
    }.elsewhen(io.bypassFromExe.regAddr === rsAddr && rsAddr =/= 0.U && io.bypassFromMem.regAddr =/= rsAddr){
        trueRSData := io.bypassFromExe.regData
    }.elsewhen(io.bypassFromExe.regAddr =/= rsAddr && rsAddr =/= 0.U && io.bypassFromMem.regAddr === rsAddr){
        trueRSData := io.bypassFromMem.regData
    }.otherwise{
        trueRSData := io.rsData
    }
    when(io.bypassFromExe.regAddr =/= rtAddr && io.bypassFromMem.regAddr =/= rtAddr){
        trueRTData := io.rtData
    }.elsewhen(io.bypassFromExe.regAddr === rtAddr && rtAddr =/= 0.U && io.bypassFromMem.regAddr === rtAddr){
        trueRTData := io.bypassFromExe.regData
    }.elsewhen(io.bypassFromExe.regAddr === rtAddr && rtAddr =/= 0.U && io.bypassFromMem.regAddr =/= rtAddr){
        trueRTData := io.bypassFromExe.regData
    }.elsewhen(io.bypassFromExe.regAddr =/= rtAddr && rtAddr =/= 0.U && io.bypassFromMem.regAddr === rtAddr){
        trueRTData := io.bypassFromMem.regData
    }.otherwise{
        trueRTData := io.rtData
    }
    // 处理A操作数和B操作数
    val signRSData = Wire(SInt(33.W))       // 计算base寄存器
    val memaddr = Wire(UInt(32.W))

    signRSData := Cat(0.U(1.W),trueRSData).asSInt()
    // LB SB LW SW的地址
    memaddr := (signRSData + offset.asSInt()).asUInt()(31,0)
    when(io.controlInfo.op === OP_SW || io.controlInfo.op === OP_SB){
        when(memaddr(22) === 0.U){
            // 访问的是BaseRam
            io.stallFromID := true.B
        }.otherwise{
            io.stallFromID := false.B
        }
    }.otherwise{
        io.stallFromID := false.B
    }
    when(io.controlInfo.ASel === FromAddrImm){
        io.exeInfo.OperA := io.pc + 8.U
        io.exeInfo.AFromReg := false.B
        io.exeInfo.ARegAddr := 0.U
    }.elsewhen(io.controlInfo.ASel === FromSA){
        io.exeInfo.OperA := Cat(0.U(27.W),sa)
        io.exeInfo.AFromReg := false.B
        io.exeInfo.ARegAddr := 0.U
    }.elsewhen(io.controlInfo.ASel === FromOffset){
        io.exeInfo.OperA := (signRSData + offset.asSInt()).asUInt()(31,0)
        io.exeInfo.AFromReg := false.B
        io.exeInfo.ARegAddr := 0.U
    }.otherwise{
        io.exeInfo.OperA := trueRSData
        io.exeInfo.AFromReg := true.B
        io.exeInfo.ARegAddr := rsAddr
    }
    when(io.controlInfo.BSel === FromZero){
        io.exeInfo.OperB := 0.U(32.W)
        io.exeInfo.BFromReg := false.B
        io.exeInfo.BRegAddr := 0.U
    }.elsewhen(io.controlInfo.BSel === FromImm){
        io.exeInfo.OperB := immAfterExt
        io.exeInfo.BFromReg := false.B
        io.exeInfo.BRegAddr := 0.U
    }.otherwise{
        io.exeInfo.OperB := trueRTData
        io.exeInfo.BFromReg := true.B
        io.exeInfo.BRegAddr := rtAddr
    }
    // 处理写的数据
    io.exeInfo.regwe := io.controlInfo.regwe
    when(io.controlInfo.wAddrSel === wAddr_31){
        io.exeInfo.wAddr := 31.U(5.W)
    }.elsewhen(io.controlInfo.wAddrSel === wAddr_rd){
        io.exeInfo.wAddr := rdAddr
    }.elsewhen(io.controlInfo.wAddrSel === wAddr_rt){
        io.exeInfo.wAddr := rtAddr
    }.otherwise{
        io.exeInfo.wAddr := 0.U(5.W)
    }
    io.exeInfo.op := io.controlInfo.op
    // 读取驱动
    io.rsAddr := rsAddr
    io.rtAddr := rtAddr
    // NPC
    val offsetAfterExt = Wire(SInt(18.W))
    offsetAfterExt := offset.asSInt() << 2
    val npc = Wire(UInt(32.W))
    val signpc = Wire(SInt(33.W))
    signpc := io.pc.asSInt()+4.S            // 延迟槽指令的带符号类型
    // 向指令寄存器发送读请求
    when(isBranchOrJump(io.controlInfo.op) === false.B){
        npc := 0.U(32.W)
        io.NPC_Type := NPC_4
    }.otherwise{
        when(io.controlInfo.op === OP_BEQ){
            when(io.exeInfo.OperA === io.exeInfo.OperB) {
                npc := (signpc + offsetAfterExt).asUInt()
                io.NPC_Type := NPC_J
            }.otherwise{
                io.NPC_Type := NPC_4
                npc := 0.U(32.W)
            }
        }.elsewhen(io.controlInfo.op === OP_BNE) {
            when(io.exeInfo.OperA =/= io.exeInfo.OperB) {
                npc := (signpc + offsetAfterExt).asUInt()
                io.NPC_Type := NPC_J
            }.otherwise{
                npc := 0.U(32.W)
                io.NPC_Type := NPC_4
            }
        }.elsewhen(io.controlInfo.op === OP_BGEZ){
            when(io.exeInfo.OperA(31) === 0.U){
                npc := (signpc + offsetAfterExt).asUInt()
                io.NPC_Type := NPC_J
            }.otherwise{
                npc := 0.U(32.W)
                io.NPC_Type := NPC_4
            }
        }.elsewhen(io.controlInfo.op === OP_BGTZ){
            when(io.exeInfo.OperA(31) === 0.U && io.exeInfo.OperA =/= 0.U) {
                npc := (signpc + offsetAfterExt).asUInt()
                io.NPC_Type := NPC_J
            }.otherwise{
                npc := 0.U(32.W)
                io.NPC_Type := NPC_4
            }
        }.elsewhen(io.controlInfo.op === OP_BLEZ) {
            when(io.exeInfo.OperA(31) === 1.U || io.exeInfo.OperA === 0.U){
                npc := (signpc + offsetAfterExt).asUInt()
                io.NPC_Type := NPC_J
            }.otherwise{
                npc := 0.U(32.W)
                io.NPC_Type := NPC_4
            }
        }.elsewhen(io.controlInfo.op === OP_J || io.controlInfo.op === OP_JAL) {
            npc := Cat(io.pc(31,28),instrAddrImm) << 2
            io.NPC_Type := NPC_J
        }.elsewhen(io.controlInfo.op === OP_JALR || io.controlInfo.op === OP_JR){
            npc := trueRSData
            io.NPC_Type := NPC_J
        }otherwise{ // OP_BLTZ
            when(io.exeInfo.OperA(31) === 1.U){
                npc := (signpc + offsetAfterExt).asUInt()
                io.NPC_Type := NPC_J
            }.otherwise{
                npc := 0.U(32.W)
                io.NPC_Type := NPC_4
            }
        }
    }
    io.NextPC := npc
    // ready&valid
    // 如果执行阶段准备好了，就可以ready了
    when(io.isLBandLW === true.B){
        when(io.wregAddr === io.rsAddr || io.wregAddr === io.rtAddr){
            io.ready_out := false.B
            io.valid_out := false.B
        }otherwise{
            io.ready_out := io.ready_in
            io.valid_out := io.valid_in
        }
    }.otherwise{
        // ready了
        io.ready_out := io.ready_in
        io.valid_out := io.valid_in
    }
}